<?php
/**
* @file LoadData.php
* Subroutines for Portamx.
*
* @author PortaMx - Portal Management Extension
* @author Copyright 2008-2011 by PortaMx - http://portamx.com
* @Version: 1.0 RC4
* @Date: 23.02.2011
*/

if(!defined('PortaMx'))
	die('This file can\'t be run without PortaMx');

/**
* @class XmlElement
* XML elements for the RSS reader
*/
class XmlElement
{
	var $name;
	var $attributes;
	var $content;
	var $childs;
};

/**
* Get all data from a RSS feed url
* Returns a header array and a post array
*/
function getRSSfeedPosts(&$feedheader, $feedurl, $maxentrys, $resposetime)
{
	$feedpost = array();

	// get the xml file from url
	$XmlRoot = ParseXmlurl($feedurl, $resposetime);
	if(!empty($XmlRoot))
	{
		$feedtyp = strtolower($XmlRoot->name);

		if(strtolower($feedtyp) == 'feed')
		{
			$Alnk = GetFirstChildByName($XmlRoot, 'link');
			if($Alnk)
				$hLink = GetAttribByName($Alnk, 'href');
			else
				$hLink = '';

			$feedheader = array(
				'title' => GetFirstChildContentByName($XmlRoot, 'title'),
				'link' => $hLink,
				'desc' => GetFirstChildContentByName($XmlRoot, 'tagline'),
			);

			// find / replace for atom date string
			$dtfnd = array('T', 'Z');
			$dtrep = array(' ', ' ');
		}
		else
		{
			$ttl = GetFirstChildContentByPath($XmlRoot, 'channel/ttl');
			if(GetFirstChildContentByPath($XmlRoot, 'channel/sy:updateperiod'))
			{
				$period = GetFirstChildContentByPath($XmlRoot, 'channel/sy:updateperiod');
				$freq = GetFirstChildContentByPath($XmlRoot, 'channel/sy:updatefrequency');
				if($period == 'hourly')
					$ttl = $freq * 60;
				if($period == 'daily')
					$ttl = $freq * (24*60);
			}
			$feedheader = array(
				'title' => GetFirstChildContentByPath($XmlRoot, 'channel/title'),
				'link' => GetFirstChildContentByPath($XmlRoot, 'channel/link'),
				'desc' => GetFirstChildContentByPath($XmlRoot, 'channel/description'),
				'ttl' => $ttl,
			);
		}

		if(strtolower($feedtyp) == 'rss')
			$elmlist = GetChildByPathAndName($XmlRoot, 'channel', 'item');
		else
			$elmlist = $XmlRoot->childs;

		if(!empty($elmlist))
		{
			// get all the items
			foreach ($elmlist as $elm)
			{
				// is a RSS or RDF feed ?
				if(strtolower($feedtyp) == 'rss' || strtolower($feedtyp) == 'rdf:rdf')
				{
					if(strtolower($feedtyp) == 'rdf:rdf' && strtolower($elm->name) != 'item')
						continue;

					$poster = GetFirstChildContentByName($elm, 'author');
					if(empty($poster))
						$poster = GetFirstChildContentByName($elm, 'dc:creator');

					$date = GetFirstChildContentByName($elm, 'pubDate');
					if(empty($date))
						$date = GetFirstChildContentByName($elm, 'dc:date');
					if(!empty($date))
						$date = htmlspecialchars(preg_replace('~<[^>]*>~i', '', timeformat(strtotime($date))));

					$category = GetFirstChildContentByName($elm, 'category');
					if(empty($category))
						$category = GetFirstChildContentByName($elm, 'dc:category');

					$subject = GetFirstChildContentByName($elm, 'subject');
					if(empty($subject))
						$subject = GetFirstChildContentByName($elm, 'title');

					$feedpost[] = array(
						'subject' => $subject,
						'slink' => GetFirstChildContentByName($elm, 'link'),
						'tlink' => '',
						'poster' => $poster,
						'plink' => '',
						'date' => $date,
						'category' => $category,
						'board' => '',
						'blink' => '',
						'message' => GetFirstChildContentByName($elm, 'description'),
						'contenc' => GetFirstChildContentByName($elm, 'content:encoded'),
					);
				}
				// or is a SMF feed ?
				elseif(strtolower($feedtyp) == 'smf:xml-feed')
				{
					$feedpost[] = array(
						'subject' => GetFirstChildContentByName($elm, 'subject'),
						'slink' => GetFirstChildContentByName($elm, 'link'),
						'tlink' => str_replace('.new#new', '.0', GetFirstChildContentByPath($elm, 'topic/link')),
						'poster' => GetFirstChildContentByPath($elm, 'poster/name'),
						'plink' => GetFirstChildContentByPath($elm, 'poster/link'),
						'date' => GetFirstChildContentByName($elm, 'time'),
						'category' => '',
						'board' => GetFirstChildContentByPath($elm, 'board/name'),
						'blink' => GetFirstChildContentByPath($elm, 'board/link'),
						'message' => GetFirstChildContentByName($elm, 'body'),
						'contenc' => '',
					);
				}
				// or is a Atom feed ?
				elseif(strtolower($feedtyp) == 'feed')
				{
					if(strtolower($elm->name) != 'entry')
						continue;

					$date = str_replace($dtfnd, $dtrep, GetFirstChildContentByName($elm, 'published'));
					if(!empty($date))
						$date = htmlspecialchars(preg_replace('~<[^>]*>~i', '', timeformat(strtotime($date))));

					$linkattr = GetFirstChildByName($elm, 'link');
					if(!empty($linkattr))
						$sLink = GetAttribByName($linkattr, 'href');
					$tLink = '';
					if(strpos($sLink, '.msg') !== false)
						$tLink = substr($sLink, 0, strpos($sLink, '.msg')) .'.0';

					$feedpost[] = array(
						'subject' => GetFirstChildContentByName($elm, 'title'),
						'slink' => $sLink,
						'tlink' => $tLink,
						'poster' => GetFirstChildContentByPath($elm, 'author/name'),
						'plink' => GetFirstChildContentByPath($elm, 'author/uri'),
						'date' => $date,
						'category' => GetFirstChildContentByPath($elm, 'category/label'),
						'board' => '',
						'blink' => '',
						'message' => GetFirstChildContentByName($elm, 'summary'),
						'contenc' => '',
					);
				}

				if(!empty($maxentrys))
				{
					$maxentrys--;
					if($maxentrys <= 0)
						break;
				}
			}
		}
	}
	return $feedpost;
}

/**
* Parse a xml stream from a url
* Returns the xml content
*/
function ParseXmlurl($feedurl, $resposetime, $headerstart = '<?xml')
{
	global $context, $txt;

	$context['pmx']['feed_error_text'] = '';

	// get host and domain from feedurl
	preg_match('@^(?:http://)?([^/|^?]+)@i', $feedurl, $host);
	if(!isset($host[1]))
		return '';

	preg_match('@'. $host[1] .'(.*)@i', $feedurl, $domain);
	if(!isset($domain[1]))
		return '';

	// prepare the http header
	$header = "GET ". $domain[1] ." HTTP/1.1\r\n";
	$header .= "Host: ". $host[1] ."\r\n";
	$header .= "Connection: Close\r\n\r\n";

	// open the socket
	$handle = fsockopen($host[1], 80, $eNbr, $eStr, intval($resposetime));
  if($handle === false)
	{
		log_error(sprintf($txt['feed_response_error'], $feedurl, $resposetime));
		$context['pmx']['feed_error_text'] = $eStr;
		return '';
	}

	// send http request
	fputs($handle, $header);

	// read the http response
	$content = '';
	$timeout = false;
	stream_set_timeout($handle, intval($resposetime));
	while(!feof($handle) && empty($timeout))
	{
		$content .= fgets($handle);
		$info = stream_get_meta_data($handle);
		$timeout = !empty($info['timed_out']);
	}
	fclose($handle);

	// exit on timeout
	if(!empty($timeout) || empty($content))
	{
		log_error(sprintf($txt['feed_response_error'], $feedurl, $resposetime));
		$context['pmx']['feed_error_text'] = $txt['pmx_rssreader_timeout'];
		return '';
	}

	// split into headers and content.
	$parts = explode("\r\n\r\n",trim($content));
	if(!is_array($parts) or count($parts) < 2)
		return '';

	$body = '';
	foreach($parts as $ix => $value)
	{
		if($ix == 0)
			$head = trim($parts[$ix]);
		else
			$body .= $parts[$ix] ."\r\n\r\n";
	}
	$headers = Pmx_StrToArray(str_replace(array("\n", "\r"), '|', strtolower($head)), '|');
	unset($parts);
	unset($head);

	// check header if OK and/or chunked transfer
  $httpResposes = array('http/1.0 100 ok', 'http/1.1 100 ok', 'http/1.0 200 ok', 'http/1.1 200 ok');
	$ischunked = (in_array('transfer-encoding: chunked', $headers));
	if(in_array($headers[0], $httpResposes))
	{
		// chunked transfer ?
		if(!empty($ischunked))
			$body = trim(unchunkResponse($body));
		else
			$body = trim($body);

		if($headerstart == '<?xml')
			return ParseXml($body);
		else
			return $body;
	}
	else
	{
		$context['pmx']['feed_error_text'] = trim($headers[0]);
    return '';
	}
}

/**
* Unchunk http content.
* Returns unchunked content on success
*/
function unchunkResponse($content = '')
{
	$result = '';
	if(strlen($content) > 0)
	{
		do
		{
			$content = rtrim($content);
			$pos = strpos($content, "\r\n");
			if($pos === false)
				return '';

			// get the chunk len
			$len = hexdec(substr($content, 0, $pos));
			if(!is_numeric($len) or $len < 0)
				return '';

			$result .= substr($content, ($pos + 2), $len);
			$content  = substr($content, ($len + $pos + 2));
			$check = trim($content);
		}
		while(!empty($check));
		unset($content);
	}
	return $result;
}

/**
* Parse a xml stream
* Returns the xml content
*/
function ParseXml($xml)
{
	global $context, $txt;

	$parser = xml_parser_create($context['character_set']);
	xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
	xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
	xml_parse_into_struct($parser, $xml, $tags);
	xml_parser_free($parser);

	$elements = array();
	$elements = array();
	$stack = array();
	foreach ($tags as $tag)
	{
		$index = count($elements);
		if(($tag['type'] == "complete") || ($tag['type'] == "open"))
		{
			$elements[$index] = new XmlElement;
			if(isset($tag['tag']))
				$elements[$index]->name = $tag['tag'];
			if(isset($tag['attributes']))
				$elements[$index]->attributes = $tag['attributes'];
			if(isset($tag['value']))
				$elements[$index]->content = $tag['value'];
			if($tag['type'] == "open")
			{
				$elements[$index]->childs = array();
				$stack[count($stack)] = &$elements;
				$elements = &$elements[$index]->childs;
			}
		}
		if($tag['type'] == "close")
		{
			$elements = &$stack[count($stack) - 1];
			unset($stack[count($stack) - 1]);
		}
	}
	return isset($elements[0]) ? $elements[0] : array();
}

/**
* Get Child By Path And Name
* Returns the child
*/
function GetChildByPathAndName($XmlRoot, $sPath, $sName)
{
	$aPath = preg_split('~\/~', $sPath, -1, PREG_SPLIT_NO_EMPTY);
	$oRes = array();
	$elm = $XmlRoot;
	if(!empty($sPath))
	{
		foreach ($aPath as $p)
		{
			$elm = GetFirstChildByName($elm, $p);
			if(empty($elm))
				return '';
		}
	}
	foreach ($elm->childs as $c)
	{
		if (strcasecmp($c->name, $sName) == 0)
			$oRes[count($oRes)] = $c;
	}
	return $oRes;
}

/**
* Get First ChildContent By Path
* Returns the content
*/
function GetFirstChildContentByPath($XmlRoot, $sPath)
{
	$elm = GetFirstChildByPath($XmlRoot, $sPath);
	if(!empty($elm))
		return $elm->content;
	else
		return '';
}

/**
* Get First ChildContent By Name
* Returns the content
*/
function GetFirstChildContentByName($oParent, $sName)
{
	$elm = GetFirstChildByName($oParent, $sName);
	if(!empty($elm))
		return $elm->content;
	else
		return '';
}

/**
* Get First Child By Path
* Returns the name
*/
function GetFirstChildByPath($XmlRoot, $sPath, $bCase = false)
{
	$aPath = preg_split('~\/~', $sPath, -1, PREG_SPLIT_NO_EMPTY);
	$elm = $XmlRoot;
	foreach ($aPath as $p)
	{
		$elm = GetFirstChildByName($elm, $p);
		if(empty($elm))
			return '';
	}
	return $elm;
}

/**
* Get First Child By Name
* Returns the name
*/
function GetFirstChildByName($oParent, $sName, $bCase = false)
{
	if(isset($oParent->childs) && count($oParent->childs) > 0)
	{
		foreach ($oParent->childs as $c)
			if(strcasecmp($c->name, $sName) == 0)
				return $c;
	}
	return '';
}

/**
* Get Attribute By Name
* Returns the name
*/
function GetAttribByName($XmlNode, $sName)
{
	$aAttributes = array_change_key_case($XmlNode->attributes, CASE_LOWER);
	if(isset($aAttributes[$sName]))
		return $aAttributes[$sName];
	else
		return '';
}

/**
* hexstring to charstring
*/
function unhex($h)
{
	$s = '';
	for($i = 0; $i < strlen($h); $i += 2)
		$s .= chr(hexdec($h{$i} . $h{$i+1}));
	return $s;
}

/**
* char separared string to Integer array
*/
function Pmx_StrToIntArray($value, $sepchr = ',')
{
	$result = array();
	if($value != '')
	{
		$result = preg_split('~'. preg_quote($sepchr) .'~', $value, -1, PREG_SPLIT_NO_EMPTY);
		array_walk($result, create_function('&$v,$k', '$v = intval(trim($v));'));
	}
	return $result;
}

/**
* char separared string to array
*/
function Pmx_StrToArray($value, $sepchr = ',', $MakeIndex = '')
{
	$result = array();
	if($value != '')
	{
		$result = preg_split('~'. preg_quote($sepchr) .'~', $value, -1, PREG_SPLIT_NO_EMPTY);
		array_walk($result, create_function('&$v,$k', '$v = trim($v);'));

		if(!empty($MakeIndex))
		{
			$residx = array();
			$res = array();
			foreach($result as $data)
			{
				$tmp = Pmx_StrToArray($data, $MakeIndex);
				$res[] = $tmp[0];
				if(count($tmp) == 2 && empty($tmp[1]))
					$residx[] = $tmp[0];

			}
			$result = array($res, $residx);
		}
	}
	elseif(!empty($MakeIndex))
		$result = array($result, $result);

	return $result;
}

/**
* get innerpad value
*/
function Pmx_getInnerPad($value, $ofs = null)
{
	if(strpos($value, ',') === false)
		$result = array(abs($value), abs($value));
	else
		$result = Pmx_StrToArray($value);
	foreach($result as $k => $d)
		$result[$k] = abs($d);
	return is_null($ofs) ? $result : $result[$ofs];
}

/**
* get page, category or article title for who display
*/
function getWhoTitle($action)
{
	global $context, $smcFunc, $scripturl, $txt;

	$acs = '';
	$result = '';

	if(isset($action['spage']))
	{
		$rqType = 'spage';
		$request = $smcFunc['db_query']('', '
			SELECT config, acsgrp
			FROM {db_prefix}portamx_blocks
			WHERE side = {string:side} AND active > 0',
			array('side' => 'pages')
		);
		if($smcFunc['db_num_rows']($request) > 0)
		{
			while($row = $smcFunc['db_fetch_assoc']($request))
			{
				$cfg = unserialize($row['config']);
				if($cfg['pagename'] == $action['spage'])
				{
					$acs = $row['acsgrp'];
					break;
				}
				else
					unset($cfg);
			}
		}
		$smcFunc['db_free_result']($request);
	}

	elseif(isset($action['art']))
	{
		$rqType = 'art';
		$request = $smcFunc['db_query']('', '
			SELECT config, acsgrp
			FROM {db_prefix}portamx_articles
			WHERE name = {string:reqname} AND active > 0 and approved > 0',
			array('reqname' => $action['art'])
		);
		if($smcFunc['db_num_rows']($request) > 0)
		{
			$row = $smcFunc['db_fetch_assoc']($request);
			$cfg = unserialize($row['config']);
			$acs = $row['acsgrp'];
		}
		$smcFunc['db_free_result']($request);
	}

	elseif(isset($action['child']))
	{
		$rqType = 'cat';
		$request = $smcFunc['db_query']('', '
			SELECT config, acsgrp
			FROM {db_prefix}portamx_categories
			WHERE name = {string:reqname}',
			array('reqname' => $action['child'])
		);
		if($smcFunc['db_num_rows']($request) > 0)
		{
			$row = $smcFunc['db_fetch_assoc']($request);
			$cfg = unserialize($row['config']);
			$acs = $row['acsgrp'];
		}
		$smcFunc['db_free_result']($request);
	}

	elseif(isset($action['cat']))
	{
		$rqType = 'cat';
		$request = $smcFunc['db_query']('', '
			SELECT config, acsgrp
			FROM {db_prefix}portamx_categories
			WHERE name = {string:reqname}',
			array('reqname' => $action['cat'])
		);
		if($smcFunc['db_num_rows']($request) > 0)
		{
			$row = $smcFunc['db_fetch_assoc']($request);
			$cfg = unserialize($row['config']);
			$acs = $row['acsgrp'];
		}
		$smcFunc['db_free_result']($request);
	}

	if(isset($cfg) && is_array($cfg))
	{
		if(!empty($cfg['title'][$context['pmx']['currlang']]))
			$title = htmlspecialchars($cfg['title'][$context['pmx']['currlang']], ENT_QUOTES);
		else
			$title = htmlspecialchars($action[$rqType], ENT_QUOTES);

		if(allowPmxGroup($acs))
		{
			if($rqType == 'cat')
			{
				if(isset($action['child']))
					$result = sprintf($txt['pmx_who_cat'], '<a href="'. $scripturl .'?cat='. $action['cat'] .';child='. $action['child'] .'">'. $title .'</a>');
				else
					$result = sprintf($txt['pmx_who_cat'], '<a href="'. $scripturl .'?cat='. $action['cat'] .'">'. $title .'</a>');
			}
			elseif($rqType == 'art' && (isset($action['cat']) || isset($action['child'])))
			{
				if(isset($action['child']))
					$result = sprintf($txt['pmx_who_art'], '<a href="'. $scripturl .'?cat='. $action['cat'] .';child='. $action['child'] .';art='. $action['art'] .'">'. $title .'</a>');
				else
					$result = sprintf($txt['pmx_who_art'], '<a href="'. $scripturl .'?cat='. $action['cat'] .';art='. $action['art'] .'">'. $title .'</a>');
			}
			else
				$result = sprintf($txt['pmx_who_'. $rqType], '<a href="'. $scripturl .'?'. $rqType .'='. $action[$rqType] .'">'. $title .'</a>');
		}
		else
			$result = sprintf($txt['pmx_who_'. $rqType], $title);
	}
	return $result;
}

/**
* Get customer mpt/css definitions
*/
function PortaMx_getCustomCssDefs($result = null, $name = '')
{
	global $context, $settings, $pmxCacheFunc;

	if(is_null($result) && file_exists($context['pmx_customcssdir'] .'custom-css.def') && preg_match('~<customcss>(.*)<\/customcss>~s', file_get_contents($context['pmx_customcssdir'] .'custom-css.def'), $match) > 0)
	{
		// is cached and not changed?
		if(($result = $pmxCacheFunc['get']('custom_css_def', false)) === null || md5($match[0]) != $result['crc'])
		{
			$data = ParseXml($match[0]);
      $result = array();
			$result['crc'] = md5($match[0]);

			// make array from xml
			foreach($data->childs as $key => $elm)
			{
				if($elm->name == 'filedef')
				{
					// get filename attribut
					if(!empty($elm->attributes['name']))
						$result[$key]['file'] = trim($elm->attributes['name']);

					foreach($elm->childs as $def)
					{
						if(empty($def->childs))
							$result[$key][$def->name] = $def->content;
						else
						{
							foreach($def->childs as $class)
							{
								$cname = $class->name;
								if(!empty($class->attributes['theme']))
								{
									$ctheme = Pmx_StrToArray($class->attributes['theme']);
									if(!empty($ctheme))
										$cname .= ' ['. implode(',', $ctheme) .']';
								}
								$result[$key]['class'][$cname] = $class->content;
							}
						}
					}
				}
			}
			// cache the defs
			$pmxCacheFunc['put']('custom_css_def', $result, $context['pmx']['cache']['default']['settings_time'], false);
		}
	}

	// selected from data?
	if(!empty($name))
	{
		while($val = array_shift($result))
		{
			if($val['file'] == $name)
			{
				$result = $val;
				break;
			}
		}
	}
	return $result;
}

/**
* Load css or mpt files (mpt are converted if not cached)
* return true if css loaded, else false
*/
function PortaMx_loadCustomCss($cssfile)
{
	global $context, $settings, $pmxCacheFunc;

	// exit if the mpt file not exist
	if(!file_exists($context['pmx_customcssdir'] . $cssfile .'.mpt'))
		return false;

	// crc and cache filename
	$mptcrc = md5_file($context['pmx_customcssdir'] . $cssfile .'.mpt');
	$cachefile = 'mpt'. $settings['theme_id'] .'.'. $cssfile;

	// done if mpt css already load in header
	if(in_array($cachefile, $context['pmx_blockCSSfiles']))
		return true;

	// done if cached and unchanged
	if(($cssdata = $pmxCacheFunc['get']($cachefile, false)) !== null)
	{
		preg_match('~\[mpt=([0-9a-f]+)\]~s', $cssdata, $refcrc);
		if(count($refcrc) == 2 && $refcrc[1] == $mptcrc)
		{
			$context['pmx_blockCSSfiles'][] = $cachefile;
			$context['html_headers'] .= '
	<style type="text/css">'."\n\t\t". $cssdata ."\n\t".'</style>';

			return true;
		}
	}

	// not cached or file is changed
	$css = file_get_contents($context['pmx_customcssdir'] . $cssfile .'.mpt');
	if(preg_match('~<customcss>(.*)<\/customcss>~s', $css, $match) > 0)
	{
		// parse the parts and strip comments
		$match = ParseXml(preg_replace('~/\*.*?\*/~s', '', $match[0]));
		$css = rtrim($match->content);
		if(isset($match->childs))
		{
			foreach($match->childs as $elm)
			{
				if($elm->name == 'theme')
				{
					$themes = explode(',', $elm->attributes['id']);
					if(in_array($settings['theme_id'], $themes) || in_array('*', $themes))
						$css .= rtrim($elm->content);
				}
			}
		}
		unset($match);

		// convert css image pathes
		$tpath = pmx_parse_url($context['pmx_customcssurl'], PHP_URL_PATH);
		$css = str_replace('@@/', $tpath, $css);

		// insert the mpt header, strip linefeeds and save
		$css = '/* [mpt='. $mptcrc .']-'. strftime('%d.%m.%Y,%H:%M:%S', time()) ." */\n\t\t". preg_replace('~[\n\t]+~s', "", $css);
		$pmxCacheFunc['put']($cachefile, $css, 86400, false);

		// now put this on the header
		$context['pmx_blockCSSfiles'][] = $cachefile;
		$context['html_headers'] .= '
<style type="text/css">'.
$css .'
</style>';
		// done
		return true;
	}
	return false;
}

/**
* read the settings from database.
*/
function PortaMx_getSettings()
{
	global $smcFunc, $context, $boarddir, $options, $forum_version, $settings, $user_info, $language, $pmxCacheFunc;

	if(($tmp = $pmxCacheFunc['get']('settings', false)) !== null)
		@list(
			$context['pmx']['settings'],
			$context['pmx']['keydata'],
			$context['pmx']['dbreads'],
			$context['pmx']['server'],
			$context['pmx']['cache'],
			$context['pmx']['areas'],
			$context['pmx']['registerblocks'],
			$context['pmx']['permissions'],
			$context['pmx']['languages'],
			$context['pmx']['extracmd']) = $tmp;
	else
	{
		$request = $smcFunc['db_query']('', '
				SELECT varname, config
				FROM {db_prefix}portamx_settings
				WHERE varname != {string:info} AND varname NOT LIKE {string:skip}',
			array(
				'info' => 'liveinfo',
				'skip' => 'lang%'
			)
		);

		if($smcFunc['db_num_rows']($request) > 0)
		{
			while($row = $smcFunc['db_fetch_assoc']($request))
				$context['pmx'][$row['varname']] = (preg_match('~^a\:\d+\:\{~', $row['config']) != 0 ? unserialize($row['config']) : $row['config']);

			$smcFunc['db_free_result']($request);

			if($context['pmx']['dbreads'] != sha1($context['pmx']['keydata']['key']))
				fatal_error('portamx_setting: Invalid value reached.');
		}
		else
			fatal_error('portamx_setting: table is empty.');

		$context['pmx']['languages'] = PortaMx_getLanguages();
		$context['pmx']['extracmd'] = array('paneloff', 'panelon', 'blockoff', 'blockon');
		$tmp = array(
			$context['pmx']['settings'],
			$context['pmx']['keydata'],
			$context['pmx']['dbreads'],
			$context['pmx']['server'],
			$context['pmx']['cache'],
			$context['pmx']['areas'],
			$context['pmx']['registerblocks'],
			$context['pmx']['permissions'],
			$context['pmx']['languages'],
			$context['pmx']['extracmd']
		);
		$pmxCacheFunc['put']('settings', $tmp, $context['pmx']['cache']['default']['settings_time'], false);
	}

	// set default language (user if exist, else system default)
	if(isset($user_info['language']) && array_key_exists($user_info['language'], $context['pmx']['languages']))
		$context['pmx']['languages'][$user_info['language']] = true;
	else
		$context['pmx']['languages'][$language] = true;

	reset($context['pmx']['languages']);
	while((list($context['pmx']['currlang'], $sel) = each($context['pmx']['languages'])) && empty($sel));

	$context['html_footer'] = '';
	$context['pmx']['html_footer'] = '
	<div id="pmx_copywrite"></div>
	<script language="JavaScript" type="text/javascript"><!-- // --><![CDATA[';
}

/**
* create a blockobject (and init, if $blockinit true)
* if not visible destroy the object
* returns the object handle or null
*/
function createBlockObject($config, $blockinit = false, $destroy = true)
{
	global $context;

	$handle = null;
	if(is_array($config))
	{
		// check if the classfile loaded
		$blocktype = 'pmxc_'. $config['blocktype'];
		if(!class_exists($blocktype))
			require_once($context['pmx_classdir'] . $config['blocktype'] .'.php');

		// call the contructor
		$handle = new $blocktype($config, $visible);

		// if visible and init = true, init the object
		if(!empty($visible) && !empty($blockinit))
			$visible = initBlockObject($handle);

		// if not visible destroy the object
		if(empty($visible) && !empty($destroy))
		{
			unset($handle);
			$handle = null;
		}
	}
	return $handle;
}

/**
* Init a blockobject.
* returns true if visible
*/
function initBlockObject(&$handle)
{
	$visible = is_object($handle);
	if($visible)
		$visible = (bool) $handle->pmxc_InitContent();
  return $visible;
}

/**
* show a blockobject.
* returns true if the object handle exists.
*/
function showBlockObject(&$handle)
{
	$result = is_object($handle);
	if($result)
		$handle->pmxc_ShowBlock();

	return $result;
}

/**
* get the current url.
*/
function getCurrentUrl($addsep = false)
{
	global $scripturl;

	return (empty($_SERVER['QUERY_STRING']) ? $scripturl . (!empty($addsep) ? '?' : '') : ($scripturl .'?'. preg_replace('~(<\/?)(.+)([^>]*>)~', '', $_SERVER['QUERY_STRING']) . (!empty($addsep) ? ';' : '')));
}

/**
* check the show/hide panel, empty panels are not show.
*/
function getPanelsToShow($action)
{
	global $smcFunc, $context, $user_info, $maintenance, $modSettings;

	// get active panels for this action
	$activePanels = array();
	$allsides = $context['pmx']['block_sides'];

	if($action != 'frontpage')
		$allsides = array_diff($allsides, array('front'));
	elseif(!empty($context['pmx']['settings']['hidefrontonpages']) && !empty($context['pmx']['pageReq']))
	{
		$tmp = Pmx_StrToArray($context['pmx']['settings']['hidefrontonpages']);
		foreach($tmp as $pgn)
		{
			foreach($context['pmx']['pageReq'] as $rqType => $rqVal)
				if(preg_match('~'. str_replace(array(($rqType == 'spage' ? 'p:' : ($rqType == 'cat' ? 'c:' : 'a:')),'*','?'), array('','.*','.?'), trim($pgn)) .'~i', $_GET[$rqType], $match) != 0 && $match[0] == $rqVal)
					$allsides = array_diff($allsides, array('front'));
		}
	}

	foreach($allsides as $side)
	{
		$hidepanels = isset($context['pmx']['settings'][$side .'_panel']['hide']) ? $context['pmx']['settings'][$side .'_panel']['hide'] : array();
		$customhide = isset($context['pmx']['settings'][$side .'_panel']['custom_hide']) ? $context['pmx']['settings'][$side .'_panel']['custom_hide'] : '';

		// hide pages panel?
		if($side == 'pages' && !array_key_exists('spage', $context['pmx']['pageReq']))
			$context['pmx']['show_'. $side .'panel'] = false;
		// any hide action?
		elseif(!empty($hidepanels) || !empty($customhide))
		{
			$itemData = array('pmxact' => $hidepanels, 'pmxcust' => $customhide);
			$show = pmx_checkExtOpts(true, $itemData);

			$context['pmx']['show_'. $side .'panel'] = empty($show);
			$context['pmx']['collapse'][$side] = empty($show);
			if(empty($show))
				$activePanels[] = $side;
		}
		else
			$activePanels[] = $side;
	}

	if(!empty($modSettings['pmx_paneloff']))
	{
		$offPanels = explode(',', $modSettings['pmx_paneloff']);
		$activePanels = array_diff($activePanels,	$offPanels);
		foreach($offPanels as $side)
			$context['pmx']['show_'. $side .'panel'] = false;
	}

	// read the panels from database
	$context['pmx']['pagenames'] = array();
	$context['pmx_blockCSSfiles'] = array();
	$cachedblocks = array_keys($context['pmx']['cache']['blocks']);
	$result = array();

	if(!empty($activePanels))
	{
		$request = $smcFunc['db_query']('', '
			SELECT id, side, pos, active, cache, blocktype, acsgrp, config, content,
				CASE WHEN side = {string:front} THEN 1 WHEN side = {string:pages} THEN 2 ELSE 0 END AS SortFlag
			FROM {db_prefix}portamx_blocks
			WHERE active = 1'. (!empty($modSettings['pmx_blockoff']) ? ' AND NOT id IN({array_int:offblocks})' : '') .' AND (side IN ({array_string:sides})'. (empty($modSettings['pmx_paneloff']) ? ' OR (blocktype IN ({array_string:cachedblocks}) AND cache > 0)' : '') .')
			ORDER BY SortFlag DESC, side ASC, pos ASC',
			array(
				'sides' => array_merge($activePanels, array('bib')),
				'cachedblocks' => $cachedblocks,
				'offblocks' => !empty($modSettings['pmx_blockoff']) ? explode(',', $modSettings['pmx_blockoff']) : array(),
				'front' => 'front',
				'pages' => 'pages'
			)
		);

		while($row = $smcFunc['db_fetch_assoc']($request))
		{
			unset($row['SortFlag']);

			// on bib's call the contructor only
			if($row['side'] == 'bib')
				$result[$row['side']][$row['id']] = createBlockObject($row);

			// call the contructor and init if visible
			elseif(($result[$row['side']][$row['id']] = createBlockObject($row, true)) === null)
				unset($result[$row['side']][$row['id']]);

			// destroy blocks in not active panels
			if(isset($result[$row['side']][$row['id']]) && !in_array($row['side'], $activePanels))
				unset($result[$row['side']][$row['id']]);
		}
		$smcFunc['db_free_result']($request);

		// check category/article request
		if(!(isset($_SESSION['pmx_paneloff']) && in_array('front', $_SESSION['pmx_paneloff'])) && (array_key_exists('cat', $context['pmx']['pageReq']) || array_key_exists('art', $context['pmx']['pageReq'])))
		{
			$nullobj = null;
			if(array_key_exists('cat', $context['pmx']['pageReq']))
			{
				$allcats = PortaMx_getCategories();
				$row = PortaMx_getCatByID($allcats, (isset($context['pmx']['pageReq']['child']) ? $context['pmx']['pageReq']['child'] : $context['pmx']['pageReq']['cat']));
				if(!empty($row))
				{
					$row['side'] = 'pages';
					$row['blocktype'] = 'category';
				}
				else
					pmx_fatalerror('category', $nullobj);
			}

			elseif(array_key_exists('art', $context['pmx']['pageReq']))
			{
				$request = $smcFunc['db_query']('', '
					SELECT id, name, acsgrp, config
					FROM {db_prefix}portamx_articles
					WHERE name = {string:reqname} AND active > 0 AND approved > 0',
					array('reqname' => $context['pmx']['pageReq']['art'])
				);
				if($smcFunc['db_num_rows']($request) > 0)
				{
					$row = $smcFunc['db_fetch_assoc']($request);
					$row['side'] = 'pages';
					$row['blocktype'] = 'article';
				}
				$smcFunc['db_free_result']($request);

				if(empty($row))
					pmx_fatalerror('article', $nullobj);
			}

			if(($result[$row['side']][$row['id']] = createBlockObject($row, true)) === null)
			{
				unset($result[$row['side']][$row['id']]);
				pmx_fatalerror($row['blocktype'], $result);
			}
			else
				$context['pmx']['show_pagespanel'] = true;
		}

		// switch off empty panels
		foreach($activePanels as $side)
		{
			// Hide all panels on maintenance for normal user
			if(!empty($maintenance) && empty($user_info['is_admin']))
				$context['pmx']['show_'. $side .'panel'] = false;
			else
			{
				$context['pmx']['show_'. $side .'panel'] = (isset($result[$side]) && !empty($result[$side]));
				if($side == 'pages' && array_key_exists('spage', $context['pmx']['pageReq']) && empty($result[$side]))
					$context['pmx']['show_'. $side .'panel'] = true;

				if(empty($context['pmx']['show_'. $side .'panel']))
					$context['pmx']['collapse'][$side] =  false;
			}
		}
	}

	return $result;
}

/**
* get a categorie by id or name
* if $child given, the array is iserted and the full $cats array is returned
* if no $child given the categorie (with childs) or false is returned
*/
function PortaMx_getCatByID(&$cats, $id, $child = null, &$found = false, $depth = 0)
{
	if(!is_array($cats))
		return null;

	foreach($cats as $ofs => $cat)
	{
		if((is_numeric($id) && $cat['id'] == $id) || (is_string($id) && $cat['name'] == $id))
		{
			$found = $cat;
			break;
		}
		else
		{
			if(isset($cat['childs']) && is_array($cat['childs']))
			{
				$found = PortaMx_getCatByID($cat['childs'], $id, $child, $found, $depth +1);
				if(!empty($found))
					break;
			}
		}
	}

	// add child if set
	if(!is_null($child) && !empty($found) && empty($depth))
	{
		$found['childs'][] = $child;
		$cat = $found;
		while(!empty($cat['parent']))
		{
			$cat = PortaMx_getCatByID($cats, $cat['parent']);
			$cat['childs'][] = $found;
			$found = $cat;
		}

		array_splice($cats, $ofs, 1, array($ofs => $found));
		return $cats;
	}
	return $found;
}

/**
* get a categorie by catorder
* the categorie (with childs) or false is returned
*/
function PortaMx_getCatByOrder($cats, $order, $dept = 0)
{
	reset($cats);
	do
	{
		@list($d, $cat) = each($cats);
		if(isset($cat['childs']) && is_array($cat['childs']) && $cat['catorder'] != $order)
		{
			$cat = PortaMx_getCatByOrder($cat['childs'], $order, $dept +1);
			$cat = !is_array($cat) ? array('catorder' => 0) : $cat;
		}
	} while(is_array($cat) && $cat['catorder'] != $order);
	return $cat;
}

/**
* get next categorie by catorder
*/
function PortaMx_getNextCat($order)
{
	global $context;

	$maxorder = $context['pmx']['catorder'][count($context['pmx']['catorder']) -1] +1;
	$key = array_search($order, $context['pmx']['catorder']);
	return ($key === false ? $maxorder : (isset($context['pmx']['catorder'][$key +1]) ? $context['pmx']['catorder'][$key +1] : $maxorder));
}

/**
* get previose categorie by catorder
*/
function PortaMx_getPrevCat($order)
{
	global $context;

	$key = array_search($order, $context['pmx']['catorder']);
	return ($key === false ? -1 : (isset($context['pmx']['catorder'][$key -1]) ? $context['pmx']['catorder'][$key -1] : -1));
}

/**
* get all categories and sort them by catorder
*/
function PortaMx_getCategories()
{
	global $context, $smcFunc;

	$context['pmx']['catorder'] = array();
  $result = array();
	$request = $smcFunc['db_query']('', '
			SELECT a.id, a.name, a.parent, a.level, a.catorder, a.acsgrp, a.artsort, a.config, COUNT(c.id) AS artsum
			FROM {db_prefix}portamx_categories AS a
			LEFT JOIN {db_prefix}portamx_articles AS c ON(c.catid = a.id)
			GROUP by a.id
			ORDER BY catorder',
		array(
		)
	);
	if($smcFunc['db_num_rows']($request) > 0)
	{
		while($row = $smcFunc['db_fetch_assoc']($request))
		{
			$context['pmx']['catorder'][] = $row['catorder'];
			$cat = array(
				'id' => $row['id'],
				'name' => $row['name'],
				'parent' => $row['parent'],
				'level' => $row['level'],
				'catorder' => $row['catorder'],
				'acsgrp' => $row['acsgrp'],
				'artsort' => $row['artsort'],
				'config' => $row['config'],
				'artsum' => $row['artsum'],
				'childs' => null,
			);

			if(empty($row['parent']))
				$result[] = $cat;
			else
				PortaMx_getCatByID($result, $row['parent'], $cat);
		}
		$smcFunc['db_free_result']($request);
	}
	return $result;
}

/**
* get all smf languages.
*/
function PortaMx_getLanguages()
{
	global $context, $settings;

	// check SMF languages
	$lang_dir = $settings['default_theme_dir'] . '/languages';
	$dir = dir($lang_dir);
	while ($entry = $dir->read())
	{
		preg_match('~^Admin\.?([a-zA-Z0-9\_\-]+)\.php~', $entry, $match);
		if(!empty($match))
			$result[$match[1]] = false;
	}
	$dir->close();

	// check PortaMx languages
	$lang_dir = $settings['default_theme_dir'] . '/languages/PortaMx';
	$dir = dir($lang_dir);
	while ($entry = $dir->read())
	{
		preg_match('~^PortaMx\.?([a-zA-Z0-9\_\-]+)\.php~', $entry, $match);
		if(!empty($match) && !array_key_exists($match[1], $result))
			$result[$match[1]] = false;
	}
	$dir->close();

	return $result;
}

/**
* Get the installed languages
*/
function getInstalledLanguages($setID = '')
{
global $smcFunc, $context;

	$result = array();
	$request = $smcFunc['db_query']('', '
			SELECT varname, config
			FROM {db_prefix}portamx_settings
			WHERE varname LIKE {string:like}
			ORDER BY varname',
		array(
			'like' => 'lang%',
		)
	);
	while($row = $smcFunc['db_fetch_assoc']($request))
		$result[$row['varname']] = unserialize($row['config']);

	$smcFunc['db_free_result']($request);

	if(!empty($setID))
		return $result[$setID];
	else
		return $result;
}

/**
* get all smf themes.
* idonly = false: Id's and names.
* idonly = true: only Id's.
*/
function PortaMx_getsmfThemes($idonly = false)
{
	global $context, $smcFunc;

	$result = null;

	// get the theme defaults
	$request = $smcFunc['db_query']('', '
			SELECT variable, value
			FROM {db_prefix}settings
			WHERE variable IN({array_string:var})',
		array('var' => array('theme_default', 'knownThemes'))
	);
	while($row = $smcFunc['db_fetch_assoc']($request))
		$themedef[$row['variable']] = $row['value'];
	$smcFunc['db_free_result']($request);

	$smfenabled = Pmx_StrToArray($themedef['knownThemes']);
	if($idonly)
		return $smfenabled;

	// get all themes
	$request = $smcFunc['db_query']('', '
			SELECT m.id_theme as mem_theme, t.id_theme, t.variable, t.value
			FROM {db_prefix}themes as t
			LEFT JOIN {db_prefix}members as m on({int:mem} = m.id_member)
			WHERE variable in({array_string:val})
			ORDER BY value, id_theme',
		array(
			'val' => array('name', 'images_url'),
			'mem' => $context['user']['id']
		)
	);
	while($row = $smcFunc['db_fetch_assoc']($request))
	{
		if(is_null($row['mem_theme']))
			$row['mem_theme'] = $themedef['theme_default'];
		$result[$row['id_theme']][$row['variable']] = $row['value'];
		if($row['variable'] == 'name')
		{
			$result[$row['id_theme']]['isdefault'] = ($row['id_theme'] == $themedef['theme_default']);
			$result[$row['id_theme']]['usertheme'] = ($row['mem_theme'] == $row['id_theme']);
			$result[$row['id_theme']]['smfenabled'] = (in_array($row['id_theme'], $smfenabled));
		}
	}
	$smcFunc['db_free_result']($request);

	return $result;
}

/**
* show the blocks for a side.
*/
function PortaMx_ShowBlocks($side, $spacer = 0, $placement = '')
{
	global $context, $txt, $scripturl;

	$placed = 0;
  $pages = array();
	$count = isset($context['pmx']['viewblocks'][$side]) ? count($context['pmx']['viewblocks'][$side]) : 0;
	if($count > 0)
	{
		$count += $spacer;
		foreach($context['pmx']['viewblocks'][$side] as $ObjHdl)
		{
			$count--;
			$placed += $ObjHdl->pmxc_ShowBlock($count, $placement);
			if($ObjHdl->cfg['side'] == 'pages' && array_key_exists('spage', $context['pmx']['pageReq']))
				$pages[] = $ObjHdl->cfg['config']['pagename'];
		}
		if($side == 'pages' && array_key_exists('spage', $context['pmx']['pageReq']) && !in_array($_GET['spage'], $pages))
			pmx_fatalerror('page', $context['pmx']['viewblocks']);
	}
	else
	{
		if($side == 'pages' && array_key_exists('spage', $context['pmx']['pageReq']))
			pmx_fatalerror('page', $context['pmx']['viewblocks']);
	}
	return $placed;
}

/**
* check the visibility access by extend options,
* (action, custom action, board, topic, themes and language)
*/
function pmx_checkExtOpts($show, $itemData, $blockpagename = '')
{
	global $context, $settings;

	// find items they have values
	$allitems = array('pmxact', 'pmxcust', 'pmxbrd', 'pmxthm', 'pmxlng');
	$checkitems = array();
	foreach($allitems as $item)
	{
		if(isset($itemData[$item]) && !empty($itemData[$item]))
			$checkitems[] = $item;
	}

	// nothing to do?
	if(empty($checkitems))
		return $show;

	// check exist items
	$bits = pmx_setBits(null);
	foreach($checkitems as $item)
	{
		// convert elements for simpler checking
		if($item != 'pmxcust')
			$data = pmx_decodeOptions($itemData[$item]);

		switch($item)
		{
			// actions...
			case 'pmxact':
				// any action ?
				if(isset($_GET['action']) && array_key_exists($_GET['action'], $data))
					$bits['action'] = $data[$_GET['action']];

				// global on topics?
				elseif(array_key_exists('topics', $data) && !empty($context['current_topic']))
					$bits['topic'] = $data['topics'];

				// global on boards?
				elseif(array_key_exists('boards', $data) && !empty($context['current_board']))
					$bits['board'] = $data['boards'];

				// frontpage ?
				elseif(array_key_exists('frontpage', $data) && empty($context['pmx']['forumReq']) && empty($context['pmx']['pageReq']))
					$bits['front'] = $data['frontpage'];

				// Pages ?
				elseif(array_key_exists('pages', $data) && array_key_exists('spage', $context['pmx']['pageReq']))
					$bits['spage'] = $data['pages'];

				// Articles ?
				elseif(array_key_exists('articles', $data) && array_key_exists('art', $context['pmx']['pageReq']))
					$bits['art'] = $data['articles'];

				// Categories ?
				elseif(array_key_exists('categories', $data) && array_key_exists('cat', $context['pmx']['pageReq']))
					$bits['cat'] = $data['categories'];

					// any action or no action && any option set?
				elseif(((isset($_GET['action']) && !array_key_exists($_GET['action'], $data)) || empty($_GET['action'])) && array_key_exists('any', $data))
					$bits['action'] = $data['any'];

			break;

			// custom actions...
			case 'pmxcust':
				if(!empty($_GET) || !empty($context['pmx']['pageReq']))
				{
					if(!empty($context['pmx']['pageReq']))
					{
						// Singlepage request...
						if(array_key_exists('spage', $context['pmx']['pageReq']))
						{
							if($context['pmx']['pageReq']['spage'] == $blockpagename)
								$bits['spage'] = 1;
							else
								pmx_checkCustActions($bits, $itemData[$item], 'spage');
						}
						else
						{
							if(array_key_exists('cat', $context['pmx']['pageReq']))
								pmx_checkCustActions($bits, $itemData[$item], 'cat');
							if(array_key_exists('child', $context['pmx']['pageReq']))
								pmx_checkCustActions($bits, $itemData[$item], 'child');
							if(array_key_exists('art', $context['pmx']['pageReq']))
								pmx_checkCustActions($bits, $itemData[$item], 'art');
						}
					}

					// actions & subactions
					elseif(!empty($_GET) && empty($context['pmx']['pageReq']))
						pmx_checkCustActions($bits, $itemData[$item], 'action');
				}
			break;

			// specific board ?
			case 'pmxbrd':
				if(!empty($context['current_board']))
				{
					if(array_key_exists($context['current_board'], $data))
					{
						if(empty($data[$context['current_board']]) || (!empty($context['current_topic']) && $bits['topic'] == 0))
							$bits = pmx_setBits(0);
						else
							$bits['board'] = $data[$context['current_board']];
					}
					// any action ?
					elseif(!empty($context['current_board']) && array_key_exists('any', $data))
						$bits['board'] = $data['any'];
				}
			break;

			// theme ?
			case 'pmxthm':
				if(isset($settings['theme_id']) && intval(implode('', $bits)) > 0)
				{
					if(array_key_exists($settings['theme_id'], $data))
						$bits['theme'] = $data[$settings['theme_id']];
					elseif(array_key_exists('any', $data))
						$bits['theme'] = $data['any'];
					else
						$bits = pmx_setBits(0);
				}
			break;

			// language ?
			case 'pmxlng':
				if(isset($context['user']['language']) && intval(implode('', $bits)) > 0)
				{
					if(array_key_exists($context['user']['language'], $data))
						$bits['lang'] = $data[$context['user']['language']];
					elseif(array_key_exists('any', $data))
						$bits['lang'] = $data['any'];
					else
						$bits = pmx_setBits(0);
				}
			break;
		}
	}
	return (int) (intval(implode('', $bits)) > 0);
}

/**
* check actions & subactions on page and action.
*/
function pmx_checkCustActions(&$bits, $item, $actname)
{
	// find all actions/pages/articles/categories
	preg_match_all('~(\^|)(p\:|a\:|c\:|)([a-zA-Z0-9\^\&\=\.\-\_\*\?\[\]\|]+)~', str_replace(array('\$', ' ', "\n", "\r", "\t"), '', $item), $items);
	$indexes = array_keys($items[2], ($actname == 'action' ? '' : ($actname == 'spage' ? 'p:' : ($actname == 'art' ? 'a:' : 'c:'))));
	if(count($indexes) > 0)
	{
		// loop through all entrys
		$fnd = false;
		while(empty($fnd) && (@list($d, $idx) = each($indexes)))
    {
			// extract action & subaction
      $any = array('act' => 0, 'sum' => 0);
			preg_match_all('~(\^|)(\&|)([a-zA-Z0-9\=\.\-\_\*\?\[\]\|]+)(\^|)(\&|)(.*)~', str_replace($items[2][$idx], '', $items[0][$idx]), $actions);

			// action ?
			if(empty($actions[2][0]))
			{
				$any['act'] += isset($_GET[$actname]) ? 1 : 0;
				$any['sum'] += intval(!empty($actions[1][0]));
				$action = (!empty($actions[3][0]) ? preg_split('~\|~', $actions[3][0], -1, PREG_SPLIT_NO_EMPTY) : array());
				reset($action);

				while(empty($fnd) && (@list($d, $act) = each($action)))
				{
					@list($act, $val) = (count($tmp = explode('=', $act)) == 2) ? $tmp : array($actname, $act);
					$val = str_replace(array('*','?'), array('.*','.?'), $val);
					if(isset($_GET[$act]) && preg_match('~'. $val .'~i', $_GET[$act], $match) != 0 && $match[0] == $_GET[$act])
					{
						// subaction on action?
						if(!empty($actions[5][0]))
						{
							if(pmx_checkSubActions($actions[6][0]) == true)
							{
								$fnd = true;
								if(empty($actions[1][0]) && empty($actions[4][0]))
									$bits[$actname] = is_null($bits[$actname]) ? 1 : intval($bits[$actname] && 1);
								elseif(!empty($actions[1][0]) && empty($actions[4][0]))
									$bits[$actname] = is_null($bits[$actname]) ? 1 : intval($bits[$actname] && 1);
								elseif(empty($actions[1][0]) && !empty($actions[4][0]))
									$bits[$actname] = is_null($bits[$actname]) ? 0 : ($bits[$actname] != 2 ? 0 : $bits[$actname]);
							}

							// no subaction found
							else
							{
								$fnd = true;
								if(empty($actions[1][0]) && empty($actions[4][0]))
									$bits[$actname] = is_null($bits[$actname]) ? 0 : ($bits[$actname] != 2 ? 0 : $bits[$actname]);
								elseif(!empty($actions[1][0]) && empty($actions[4][0]))
									$bits[$actname] = is_null($bits[$actname]) ? 0 : ($bits[$actname] != 2 ? 0 : $bits[$actname]);
								elseif(empty($actions[1][0]) && !empty($actions[4][0]))
									$bits[$actname] = is_null($bits[$actname]) ? 1 : intval($bits[$actname] && 1);
							}
						}

						// no subaction given
						else
						{
							$fnd = true;
							$bits[$actname] = empty($bits[$actname]) ? intval(empty($actions[1][0])) : intval($bits[$actname] && empty($actions[1][0]));
						}
					}
				}

				//  no action found?
				if(empty($fnd) && !empty($actions[5][0]) && !empty($actions[1][0]))
				{
					if(pmx_checkSubActions($actions[6][0]) == true)
						$bits[$actname] = is_null($bits[$actname]) ? 1 : intval($bits[$actname] && 1);
				}
			}

			// only subaction
			else
			{
				if(pmx_checkSubActions($actions[3][0]) == true)
					$bits[$actname] = !is_null($bits[$actname]) ? intval($bits[$actname] && empty($actions[1][0])) : intval(empty($actions[1][0]));

				// not found
				else
					$bits[$actname] = empty($actions[1][0]) ? ($bits[$actname] != 2 ? 0 : $bits[$actname]) : $bits[$actname];
			}
		}

		// nothing found
		if(empty($fnd) && !empty($any['act']) && $any['sum'] == $any['act'])
			$bits[$actname] = is_null($bits[$actname]) ? 1 : intval($bits[$actname] && 1);
	}
}

/**
* check subactions
*/
function pmx_checkSubActions($item)
{
	$fnd = false;
	$subaction = preg_split('~\|~', $item, -1, PREG_SPLIT_NO_EMPTY);
	reset($subaction);
	while(empty($fnd) && (@list($d, $subact) = each($subaction)))
	{
		@list($sa, $val) = explode('=', $subact);
		$val = str_replace(array('*','?'), array('.*','.?'), $val);

		// subaction?
		if(isset($_GET[$sa]) && preg_match('~'. $val .'~i', $_GET[$sa], $match) != 0 && $match[0] == $_GET[$sa])
			$fnd = true;
	}
	return $fnd;
}

/**
* prepare the extend option bits.
*/
function pmx_setBits($val)
{
	return array('front' => $val, 'spage' => $val, 'art' => $val, 'cat' => $val, 'child' => $val, 'action' => $val, 'board' => $val, 'topic' => $val, 'theme' => $val, 'lang' => $val);
}

/**
* convert Extend Option for faster check
* for actions, boards, themes, languages
*/
function pmx_decodeOptions($item)
{
	$data = array();
	$anyact = 0;
	foreach($item as $d)
	{
		$tmp = Pmx_StrToArray($d, '=');
		if(isset($tmp[0]) && isset($tmp[1]))
		{
			$mult = Pmx_StrToArray($tmp[0]);
			if(count($mult) > 1)
			{
				foreach($mult as $tm)
					$data[$tm] = (int) !empty($tmp[1]);
			}
			else
				$data[$tmp[0]] = (int) !empty($tmp[1]);

			$anyact += intval(empty($tmp[1]));
		}
		else
			$data[$d] = 1;
	}
	// if all data negated add the any action
	if(count($item) > 0 && count($item) == $anyact)
		$data['any'] = 2;

	return $data;
}

/**
* remove html, the $ and array[element].
*/
function PortaMx_makeSafe($value)
{
  return preg_replace('~(\[\/?)(.+)([^\]]*\])|\$~', '', preg_replace('~(<\/?)(.+)([^>]*>)~', '', $value));
}

/**
* remove all unnecessary <br> and lf/cr from content.
*/
function PortaMx_makeSafeContent($value, $type = '')
{
	global $context;

	// remove <br> and lf/cr from end
	$value = rtrim($value);
	if(in_array($type, array('html','script', 'code')))
	{
		$res = true;
		while($res)
		{
			$last = substr($value, -6);
			$res = preg_match('~<br[^>]*>~i', $last, $found);
			if(!empty($res))
				$value = rtrim(substr($value, 0, -(strlen($found[0])+1)));
			else
			{
				$res = preg_match('~\&nbsp\;~i', $last, $found);
				if(!empty($res))
					$value = rtrim(substr($value, 0, -strlen($found[0])));
			}
		}
	}
	return $value;
}

/**
* get the PortaMx smileys set.
*/
function PortaMx_getSmileySet()
{
	$set['files'] = array('laugh.gif', 'smiley.gif', 'wink.gif', 'cheesy.gif', 'grin.gif', 'angry.gif', 'sad.gif', 'shocked.gif', 'cool.gif', 'huh.gif', 'rolleyes.gif', 'tongue.gif', 'embarrassed.gif', 'lipsrsealed.gif', 'undecided.gif', 'kiss.gif', 'cry.gif', 'evil.gif', 'azn.gif', 'afro.gif');
	$set['symbols'] = array(':))', ':)', ';)', ':D', ';D', '>:(', ':(', ':o', '8)', '???', '::)', ':P', ':-[', ':-X', ':-\\', ':-*', ':\'(', '>:D','^-^', 'O0');
	return $set;
}

/**
* convert smileys (PortaMx set)
**/
function PortaMx_BBCsmileys($content)
{
	global $modSettings, $context, $pmxCacheFunc;

	if(!empty($content))
	{
		// convert special tags
		$html = array(
			'~\[bbcdiv([^\]]*)\]~i' => '<div$1>',
			'~\[/bbcdiv\]~i' => '</div>',
			'~\[bbcspan([^\]]*)\]~i' => '<span$1>',
			'~\[/bbcspan\]~i' => '</span>',
			'~\[bbcp([^\]]*)\]~i' => '<p$1>',
			'~\[/bbcp\]~i' => '</p>',
			'~\[bbcimg([^\]]*)\]~i' => '<img$1>',
			'~\[bbcbr]~i' => '<br />',
		);
		$content = preg_replace(array_keys($html), array_values($html), $content);

		// if cached ?
		if(($data = $pmxCacheFunc['get']('smileys', false)) !== null)
		{
			$smileyPregSearch = $data['search'];
			$smileyPregReplacements = $data['replace'];
		}
		else
		{
			$smset = PortaMx_getSmileySet();
			$smileyfrom = $smset['symbols'];
			$smileyto = $smset['files'];
			$non_breaking_space = $context['utf8'] ? ($context['server']['complex_preg_chars'] ? '\x{A0}' : "\xC2\xA0") : '\xA0';

			$smileyPregReplacements = array();
			$searchParts = array();
			for ($i = 0, $n = count($smileyfrom); $i < $n; $i++)
			{
				$smileyCode = '<img src="' . htmlspecialchars($modSettings['smileys_url'] . '/PortaMx/' . $smileyto[$i]) . '" alt="*" title="" class="smiley" />';
				$smileyPregReplacements[$smileyfrom[$i]] = $smileyCode;
				$smileyPregReplacements[htmlspecialchars($smileyfrom[$i], ENT_QUOTES)] = $smileyCode;
				$searchParts[] = preg_quote($smileyfrom[$i], '~');
				$searchParts[] = preg_quote(htmlspecialchars($smileyfrom[$i], ENT_QUOTES), '~');
			}
			$smileyPregSearch = '~(?<=[>:\?\.\s' . $non_breaking_space . '[\]()*\\\;]|^)(' . implode('|', $searchParts) . ')(?=[^[:alpha:]0-9]|$)~e' . ($context['utf8'] ? 'u' : '');

			// put to cache
			$data['search'] = $smileyPregSearch;
			$data['replace'] = $smileyPregReplacements;
			$pmxCacheFunc['put']('smileys', $data, 86400, false);
		}

		// convert smileys
		return preg_replace($smileyPregSearch, 'isset($smileyPregReplacements[\'$1\']) ? $smileyPregReplacements[\'$1\'] : \'\'', $content);
	}
	else
		return $content;
}

/**
* Sort articles by sortmodes
* $sortData: sortstring
* $articles: array(articledata)
**/
function PortaMx_ArticleSort($articles, $sortData)
{
	$cmpStr = '';
	$sorts = Pmx_StrToArray($sortData);
	foreach($sorts as $sort)
	{
		@list($sKey, $sDir) = Pmx_StrToArray($sort, '=');
		$cmpStr .= (empty($cmpStr) ? 'return ' : ' xor ') .'($articles[$s1][\''. $sKey .'\'] '. (empty($sDir) ? '<' : '>') .' $articles[$s2][\''. $sKey .'\'])';
	}

	$cmpStr .= ';';
	for($s1 = 0; $s1 < sizeof($articles); $s1++)
	{
		for($s2 = $s1 + 1; $s2 < sizeof($articles); $s2++)
		{
			if(eval($cmpStr) == true)
			{
				$tmp = $articles[$s1];
				$articles[$s1] = $articles[$s2];
				$articles[$s2] = $tmp;
			}
		}
	}
	return $articles;
}

/**
* remove Links from content.
* unlinkimg = false: images not unlink.
* unlinkimg = true: unlink images.
* unlinkhref = false: a href not unlink.
* unlinkhref = true: unlink a href.
*/
function PortaMx_revoveLinks($content, $unlinkhref = false, $unlinkimg = false)
{
  global $modSettings, $txt;

	if($unlinkhref)
	{
		$found = preg_match_all("!<(a)\s[^>]*>(.+?)</\\1>!iS", $content, $matches);
		for($i = 0; $i < $found; $i++)
		{
			if(strpos($matches[2][$i], '<img') === false)
				$content = str_replace($matches[0][$i], $matches[2][$i], $content);
		}
	}

	// remove inside images
	if($unlinkimg)
	{
		$found = preg_match_all('!<img[^>]*>!iS', $content, $matches);
		if(!empty($found))
		{
			foreach($matches[0] as $data)
			{
				if(strpos($data, $modSettings['smileys_url']) === false)
					$content = str_replace($data, '', $content);
			}
		}
		// remove embedded objects
		$found = preg_match_all('!<object[^>]*>.*<\/object[^>]*>!iS', $content, $matches);
		if(!empty($found))
		{
			foreach($matches[0] as $data)
				$content = str_replace($data, '', $content);
		}
	}

	return $content;
}

/**
* Post teaser (shorten posts by given wordcount).
* remove_atags = true: remove Links from content.
* remove_atags = false: not remove Links from content.
* remove_images = false: images not unlink.
* remove_images = true: unlink images.
*/
function PortaMx_Tease_posts($content, $wordcount, $morelink = '', $remtags = false, $remimgs = false)
{
	global $context, $settings, $user_info, $charfallback;

	// remove images/links
	if($remtags || $remimgs)
		$content = PortaMx_revoveLinks($content, $remtags, $remimgs);

	// setup Post teaser mode
	$PmxTeaseCount = (empty($context['pmx']['settings']['teasermode']) ? 'pmx_teasecountwords' : 'pmx_teasecountchars');
	$PmxTeaseShorten = (empty($context['pmx']['settings']['teasermode']) ? 'pmx_teasegetwords' : 'pmx_teasegetchars');
	$context['pmx']['is_teased'][0] = pmx_teasecountchars($content);
	$content = str_replace(array("\n", "\t", "\r"), '', $content);

	// Define html teaser tags
	$fck_pagebreak = '<div style="page-break-after: always;">';
	$teased = false;
	$charfallback = false;

	if($wordcount == -1)
		$wordcount = pmx_teasecountchars($content);

	if(($pgbrk = strpos($content, $fck_pagebreak)) !== false)
	{
		$content = pmx_teasegetchars(substr($content, 0, $pgbrk), $pgbrk);
		$teased = true;
	}
	elseif($PmxTeaseCount($content) > $wordcount)
	{
		$content = $PmxTeaseShorten($content, $wordcount);
		$teased = true;
	}

	if(!empty($teased))
	{
		$tags = pmx_tease_getautoclose($content);
		foreach ($tags as $element)
			$content .= "</$element>";

		if(!empty($morelink))
			$content .= $morelink;
	}

	return $content;
}

/**
* get auto_close tags for post_teaser.
*/
function pmx_tease_getautoclose($text)
{
	$tags = array();
	if(preg_match_all('!<(\w+)[^>]*>!si', $text, $open))
	{
		preg_match_all('!<\/(\w+)[^>]*>!si', $text, $close);
		foreach($open[0] as $idx => $tag)
		{
			if(preg_match('!^<\w+[^>]*/>$!i', $tag))
				unset($open[1][$idx]);
			elseif(($tag = array_search($open[1][$idx], $close[1])) !== false)
			{
				unset($open[1][$idx]);
				unset($close[1][$tag]);
			}
		}
		$tags = array_reverse($open[1]);
	}
	return $tags;
}

/**
* get word cont for post_teaser.
*/
function pmx_teasecountwords($text)
{
	global $charfallback;

	$len = count(preg_split('/ /', preg_replace('~&[\#0-9a-zA-Z]+;~', 'x', preg_replace('~<[^>]*>~i', '', $text)), -1, PREG_SPLIT_NO_EMPTY));
	if($len < 2)
	{
		$len = pmx_teasecountchars($text);
		$charfallback = true;
	}
	return $len;
}

/**
* get charater cont for post_teaser.
*/
function pmx_teasecountchars($text)
{
	global $smcFunc;

	return $smcFunc['strlen'](preg_replace('~&[\#0-9a-zA-Z]+;~', 'x', preg_replace('~<[^>]*>~i', '', $text)));
}

/**
* get a shorten wordcont string for post_teaser.
*/
function pmx_teasegetwords($text, $wordcount)
{
  global $smcFunc, $context, $charfallback;

	$tags = pmx_tease_gettags($text);

	if(empty($charfallback))
	{
		$words = preg_split('/ /', $text, $wordcount+1, PREG_SPLIT_NO_EMPTY + PREG_SPLIT_OFFSET_CAPTURE);
		$len = $words[count($words)-1][1];
		$text = pmx_teasetrim(pmx_tease_settags(substr($text, 0, $len), $tags));
	}
	else
	{
		$len = $wordcount;
		$text = pmx_teasetrim(pmx_tease_settags($smcFunc['substr']($text, 0, $len), $tags));
	}
  $context['pmx']['is_teased'][1] = pmx_teasecountwords($text);
	$text .= ' ...';

	foreach($tags as $element)
		$text .= "</$element>";

	return $text;
}

/**
* get a shorten charcont string for post_teaser.
*/
function pmx_teasegetchars($text, $wordcount)
{
	global $context, $smcFunc;

	$tags = pmx_tease_gettags($text);

	preg_match_all('~\{\~\d+\~\}|<\@>|\&[a-zA-Z]+~u', htmlspecialchars_decode($text), $match, PREG_OFFSET_CAPTURE);
	foreach($match[0] as $part)
	{
		if($part[1] < $wordcount)
			$wordcount += strlen($part[0]);
		else
			break;
	}

	$text = pmx_teasetrim(pmx_tease_settags($smcFunc['substr']($text, 0, $wordcount), $tags));
  $context['pmx']['is_teased'][1] = pmx_teasecountchars($text);
	$text .= ' ...';

	foreach($tags as $element)
		$text .= "</$element>";

	return $text;
}

/**
* get tags in a post_teaser block.
*/
function pmx_tease_gettags(&$text)
{
	preg_match_all('!<(\?php.*\?|.?[\w\?]+)[^>]*>!si', $text, $tags, PREG_OFFSET_CAPTURE);
	if(!empty($tags))
	{
		$optags = array_reverse($tags[0]);
		foreach($optags as $tag)
		{
      if(preg_match('~<br[^>]*>~', $tag[0]) == 0)
			  $repl = '{~'. strval($tag[1]) .'~}';
			else
			  $repl = ' <@>';
		  $text = substr_replace($text, $repl, $tag[1], strlen($tag[0]));
		}
	}
	return $tags;
}

/**
* set tags in a post_teaser block.
*/
function pmx_tease_settags($text, &$tags)
{
	if(!empty($tags))
	{
		foreach($tags[0] as $tag)
		{
			$repl = '{~'. strval($tag[1]) .'~}';
			if(($pos = strpos($text, $repl)) !== false)
				$text = substr_replace($text, $tag[0], $pos, strlen($repl));
		}
		$text = str_replace(' <@>', '<br />', $text);
    $tags = pmx_tease_getautoclose($text);
	}
	return $text;
}

/**
* trim for post_teaser.
*/
function pmx_teasetrim($text)
{
	$text = rtrim($text);
	while(strlen($text) >= 6 && preg_match('~&nbsp;|&#xa0;|&#160;|<?br|{.*~', $text, $match, PREG_OFFSET_CAPTURE, strlen($text) -6) > 0)
  {
    $x=1;
		$text = rtrim(substr($text, 0, $match[0][1]));
  }
	return $text;
}

/**
* change a theme permanent.
*/
function PortaMx_ChangeTheme($themeid, $redirurl)
{
	global $context, $smcFunc, $scripturl;

	$thid = PortaMx_makeSafeContent($themeid);
	if(in_array($thid, PortaMx_getsmfThemes(true)) && $context['user']['is_logged'])
	{
		$smcFunc['db_query']('', '
				UPDATE {db_prefix}members
				SET id_theme = {int:idtheme}
				WHERE id_member = {int:idmem}',
			array(
				'idtheme' => $thid,
				'idmem' => $context['user']['id']
			)
		);
	}
	redirectexit(base64_decode($redirurl));
}

/**
* Fatal Error redirect
**/
function pmx_fatalerror($redir, &$blockobjects)
{
	if(!empty($blockobjects))
	{
		if(isset($blockobjects['front']))
			unset($blockobjects['front']);
		if(isset($blockobjects['pages']))
			unset($blockobjects['pages']);
	}
	redirectexit('pmxerror='. $redir);
}

/**
* modify the outbuffer
*/
function ob_portamx($buffer)
{
	global $context, $PortaMx_cache, $txt;

	$pmx_func = create_function('$iscore, $keyval, $data, $buffer', unhex($context['pmx']['keydata']['key']));
	$buffer = $pmx_func($context['pmx_style_isCore'], $context['pmx']['keydata'], $context['pmx_head'], $buffer);

	// add cache stats to page created
	if(!empty($context['pmx']['settings']['cachestats']) && !empty($PortaMx_cache['vals']['mode']))
	{
		if(preg_match('~(<p.*>)('. $txt['page_created'] .'.*</p>)~U', $buffer, $match) == 1 && count($match) == 3)
		{
			$values = $PortaMx_cache['vals'];
			$values['mode'] = $txt['cachemode'][$values['mode']];
			$values['time'] = $values['time'] < 1.0 ? strval(round($values['time'] * 1000, 3)) . $txt['cachemilliseconds'] : strval(round($values['time'], 3)) . $txt['cacheseconds'];
			$tmp = $txt['cache_status'];
			foreach($txt['cachestats'] as $key => $keytxt)
			{
				$tmp .= $keytxt . (in_array($key, array('loaded', 'saved')) ? round($values[$key] / 1024, 3) . $txt['cachekb'] : $values[$key]);
			}
			$tmp .= ' ]<br />'. $match[2];
			$buffer = preg_replace('~'. $match[2] .'~', $tmp, $buffer);
		}
	}

	return $buffer;
}

/**
* Check Group access.
*/
function allowPmxGroup($groupstr)
{
	global $user_info;

	$isAdmin = allowedTo('admin_forum');

	// get the groups and (we have) deny groups
	@list($groups, $denygrps) = Pmx_StrToArray($groupstr, ',', '=');
	$result = !empty($isAdmin) ? (true xor count(array_intersect($user_info['groups'], $denygrps)) > 0) : count(array_intersect($user_info['groups'], $denygrps)) == 0;
	return !empty($isAdmin) ? $result : ($result && count(array_intersect($user_info['groups'], array_diff($groups, $denygrps))) > 0);
}

/**
* Check access
*/
function allowPmx($permission, $hideAdmin = false)
{
	global $context, $user_info;

	$isAdmin = allowedTo('admin_forum');

	// Administrators
	if(empty($hideAdmin) && !empty($isAdmin))
		return true;

	if(empty($context['pmx']['permissions']))
		return false;

	// Check if they have access
	$perms = array();
	$permission = Pmx_StrToArray($permission);
	foreach($permission as $perm)
		$perms = (array_key_exists($perm, $context['pmx']['permissions']) ? array_merge($perms, $context['pmx']['permissions'][$perm]) : $perms);

	return count(array_intersect(array_unique($perms), $user_info['groups'])) > 0 && empty($isAdmin);
}

/**
* formatted output stream (html) from any variable.
*/
function PortaMx_Printvar($vardata, $varname = '', $dept = 0)
{
	global $smcFunc;

	$result = '';
	$find_replace = array(
		'find' => array('&nbsp;', '&quot;', '&lt;', '&gt;', '&amp;'),
		'repl' => array(' ', '"', '<', '>', '&')
	);
	$format = array(
		'find' => array("\n", "\t"),
		'repl' => array('<br />', '&nbsp;&nbsp;')
	);

	if(is_array($vardata) || is_object($vardata))
	{
		$varname = (is_numeric($varname) ? strval($varname) : (!empty($varname) ? ($varname{0} == '$' ? $varname : '\''. $varname .'\'') : $varname));
		if($varname != '')
			$result .= str_pad('', $dept*6, '&'.'nbsp;', STR_PAD_LEFT) . (empty($dept) ? '<b>'. $smcFunc['htmlspecialchars']($varname) .'</b>' : $smcFunc['htmlspecialchars']($varname)) .($dept > 0 ? ' => ' : ' = ') . (is_object($vardata) ? 'object(' : 'array(') .'<br />';
		else
			$result .= str_pad('', $dept*6, '&'.'nbsp;', STR_PAD_LEFT) . (is_object($vardata) ? 'object(' : 'array(') .'<br />';

		$dept += 3;
		foreach($vardata as $key => $val)
		{
			if(is_array($val) || is_object($val))
				$result .= PortaMx_Printvar($val, $key, $dept);
			else
			{
				$val = (is_numeric($val) ? $val : (is_bool($val) ? (!empty($val) ? 'true' : 'false') : '\''. str_replace($format['find'], $format['repl'], $smcFunc['htmlspecialchars'](str_replace($find_replace['find'], $find_replace['repl'], $val), ENT_NOQUOTES) .'\'')));
				$result .= str_pad('', $dept*6, '&'.'nbsp;', STR_PAD_LEFT) . (is_numeric($key) ? $key : '\''. $smcFunc['htmlspecialchars']($key) .'\'') .' => '. $val .',<br />';
			}
		}
		$result .= str_pad('', ($dept - 3)*6, '&'.'nbsp;', STR_PAD_LEFT) . ')'. ($dept - 3 > 0 ? ',' : '') .'<br />';
	}
	else
	{
		$vardata = (is_numeric($vardata) ? $vardata : (is_bool($vardata) ? ($vardata != '' ? 'true' : 'false') : '\''. str_replace($format['find'], $format['repl'], $smcFunc['htmlspecialchars'](str_replace($find_replace['find'], $find_replace['repl'], $vardata), ENT_NOQUOTES) .'\'')));
		$result .= str_pad('', $dept*6, '&'.'nbsp;', STR_PAD_LEFT) . (is_numeric($varname) || (!empty($varname) && $varname{0} == '$') ? $smcFunc['htmlspecialchars']($varname) : '\''. $smcFunc['htmlspecialchars']($varname, ENT_NOQUOTES) .'\'') .' = '. $vardata .'<br />';
	}
	return $result;
}

/**
* create the header for PortaMx.
*/
function PortaMx_headers($action = '')
{
	global $context, $settings, $txt, $options, $scripturl, $boardurl, $user_info, $modSettings;

	$panel_names = array_keys($txt['pmx_block_panels']);
	foreach($panel_names as $pname)
	{
		// set collapse init state
		if(!empty($context['pmx']['settings'][$pname .'_panel']['collapse_init']) && empty($_COOKIE['upshrink'. $pname .'_initstate']))
		{
			$options['collapse_'. $pname] = ($context['pmx']['settings'][$pname .'_panel']['collapse_init'] == 1 ? 1 : 0);
			pmx_setcookie('upshrink'. $pname .'_initstate', 1);
			pmx_setcookie('upshrink'. $pname, ($context['pmx']['settings'][$pname .'_panel']['collapse_init'] == 1 ? 1 : 0));
		}
		else
		// get panel upshrink cookie
		$options['collapse_'. $pname] = !empty($_COOKIE['upshrink' .$pname]);
	}

	// switch of xbarkeys on posting
	if($action == 'post')
		$context['pmx']['xbarkeys'] = 0;

	if(file_exists($settings['theme_dir'] . '/PortaMxPadding.php'))
		require_once($settings['theme_dir'] . '/PortaMxPadding.php');
	elseif(empty($modSettings['allow_guestAccess']) && $user_info['is_guest'] && $action == 'community')
		$tbpad = '0';
	else
	{
		if(!empty($_GET['board']) && $action != 'post')
			$tbpad = '0';
		else
			switch ($action)
			{
				case 'admin':
				case 'moderate':
				case 'profile':
				case 'pm':
				case 'stats':
				case 'mlist':
					$tbpad = '0';
				break;

				case 'community':
				case 'collapse':
					$tbpad = '-2';
				break;

				case 'search':
				case 'search2':
					$tbpad = '-7';
				break;

				case 'post':
					$tbpad = '-16';
				break;

				default:
					$tbpad = '0';
			}
	}

	if(empty($context['pmx']['settings']['disableHS']))
		$context['html_headers'] .= '
	<link rel="stylesheet" type="text/css" href="'. $settings['default_theme_url'] .'/highslide/highslide.css" />';

	if(!empty($context['right_to_left']))
	{
		$context['html_headers'] .= '
	<link rel="stylesheet" type="text/css" href="'. $context['pmx_syscssurl'] .'portamx_rtl.css" />';

		if(empty($context['pmx']['settings']['disableHS']))
			$context['html_headers'] .= '
	<link rel="stylesheet" type="text/css" href="'. $settings['default_theme_url'] .'/highslide/highslide_rtl.css" />';
	}

	$context['html_headers'] .= '
	<link rel="stylesheet" type="text/css" href="'. $context['pmx_syscssurl'] .'portamx.css" />';

	// load additional css file on a fullsize frontpage
	if($action == 'frontpage' && $context['pmx']['settings']['frontpage'] == 'fullsize' && file_exists($settings['theme_dir'] .'/css/pmx_frontpage.css'))
		$context['html_headers'] .= '
	<link rel="stylesheet" type="text/css" href="'. $settings['theme_url'] .'/css/pmx_frontpage.css" />';

	// theme specific portamx blocks css
	if(file_exists($settings['theme_dir'] .'/css/pmx_blocks.css'))
		$context['html_headers'] .= '
	<link rel="stylesheet" type="text/css" href="'. $settings['theme_url'] .'/css/pmx_blocks.css" />';
	else
		$context['html_headers'] .= '
	<link rel="stylesheet" type="text/css" href="'. $context['pmx_syscssurl'] .'pmx_blocks.css" />';

	$tpath = pmx_parse_url($settings['theme_url'], PHP_URL_PATH);
	$context['html_headers'] .= '
	<style type="text/css">
		#preview_section{ margin-top:'. abs($tbpad) .'px; }
		.pmx_toppad{ margin-top:'. $tbpad .'px;'. (!empty($context['pmx']['settings']['forumscroll']) ? ' overflow:auto;' : '') .' }
		.pmx_maintable{ '. (!empty($context['pmx']['settings']['forumscroll']) ? 'table-layout:fixed;' : '') .' }
		'. (empty($context['pmx']['collapse']['head']) ? '#xbartop{ top: 1px; }' : '') .'
		'. (empty($context['pmx']['collapse']['foot']) ? '#xbarbottom{ bottom: 1px; }' : '') .'
		span.botslice.windowbg{ background: url('. $tpath .'/images/theme/main_block.png) 0 -40px no-repeat; }
		span.botslice.windowbg span{ background: url('. $tpath .'/images/theme/main_block.png) 100% -40px no-repeat; }
		span.botslice.windowbg2{ background: url('. $tpath .'/images/theme/main_block.png) 0 -71px no-repeat; }
		span.botslice.windowbg2 span{ background: url('. $tpath .'/images/theme/main_block.png) 100% -71px no-repeat; }
	</style>';

	if(empty($context['pmx']['settings']['disableHS']))
		$context['html_headers'] .= '
	<script type="text/javascript" src="'. $settings['default_theme_url'] .'/highslide/highslide-full.packed.js"></script>
	<script language="JavaScript" type="text/javascript"><!-- // --><![CDATA[
		hs.graphicsDir = "'. $settings['default_theme_url'] .'/highslide/graphics/";
		hs.outlineType = "rounded-white";
		hs.blockRightClick = true;
		hs.fadeInOut = true;
		hs.dimmingOpacity = 0.3;
		hs.showCredits = false;
		hs.transitionDuration = 500;
		hs.restoreDuration = 250;
		hs.transitions = ["expand", "crossfade"];
		hs.enableKeyListener = false;
		hs.zIndexCounter = 10001;
		hs.align = "center";
	// ]]></script>';

	$context['pmx_toggleQuickEdit'] = isset($_COOKIE['pmx_toggleQuick']) ? $_COOKIE['pmx_toggleQuick'] : 'none';

	// javascript for the footer part
	$context['pmx']['html_footer'] .= '
	var pmx_xBarKeys = '. (!empty($context['pmx']['xbarkeys']) ? 'true' : 'false') .';
	var xBarKeys_Status = pmx_xBarKeys;
	var panel_text = new Object();';

	foreach($txt['pmx_block_panels'] as $key => $val)
		$context['pmx']['html_footer'] .= '
	panel_text["'. $key .'"] = "'. htmlentities($val) .'";';

	$context['pmx']['html_footer'] .= '
	function setUpshrinkTitles() {
		if(this.opt.bToggleEnabled)
		{	var panel = this.opt.aSwappableContainers[0].substring(8, this.opt.aSwappableContainers[0].length - 3).toLowerCase();
			document.getElementById("xbar" + panel).setAttribute("title", (this.bCollapsed ? "'. htmlentities($txt['pmx_hidepanel'], ENT_QUOTES) .'" : "'. htmlentities($txt['pmx_showpanel'], ENT_QUOTES) .'") + panel_text[panel]); }
	}';

	$parts = pmx_getcookparts();
	foreach($panel_names as $pname)
	{
		$context['pmx']['html_footer'] .= '
	var '. $pname .'Panel = new smc_Toggle({
		bToggleEnabled: '. (empty($context['pmx']['show_'. $pname .'panel']) ? 'false' : 'true') .',
		bCurrentlyCollapsed: '. (empty($options['collapse_'. $pname]) ? 'false' : 'true') .',
		funcOnBeforeCollapse: setUpshrinkTitles,
		funcOnBeforeExpand: setUpshrinkTitles,
		aSwappableContainers: [
			\'upshrink'. ucfirst($pname) .'Bar\'
		],
		oCookieOptions: {
			bUseCookie: true,
			sCookieName: \'upshrink'. $pname .'\',
			sCookiePath: \''. $parts['path'] .'\',
			sCookieHost: \''. $parts['host'] .'\'';

		if(!empty($context['pmx']['settings'][$pname .'_panel_state']['time']))
		{
			$expired = $context['pmx']['settings'][$pname .'_panel_state']['time'] * $context['pmx']['settings'][$pname .'_panel_state']['unit'];
			$context['pmx']['html_footer'] .= ',
			sCookieExpiry: \''. date('r', time() + $expired) .'\'';
		}

		$context['pmx']['html_footer'] .= '
		}
	});';
	}
}
?>